package org.kosmix.kosmosfs.access;

import java.nio.ByteBuffer;
import java.util.Date;
import java.util.Random;

public class KfsTest {
	private static Random randGen = new Random(100L);

	public static void assertEquals(long v1, int v2) throws Exception {
		if (v1 != v2)
			throw new Exception("Mismatch: " + v1 + " does not match: " + v2);
	}

	public static void main(String[] args) throws Exception {
		if (args.length < 1) {
			System.out.println("Usage: KfsTest <meta server> <port>");
			System.exit(1);
		}
		try {
			int port = Integer.parseInt(args[1].trim());
			KfsAccess kfsAccess = new KfsAccess(args[0], port);

			String basedir = new String("jtest");

			if ((!kfsAccess.kfs_exists(basedir))
					&& (kfsAccess.kfs_mkdirs(basedir) != 0)) {
				System.out.println("Unable to mkdir");
				System.exit(1);
			}

			if (!kfsAccess.kfs_isDirectory(basedir)) {
				System.out.println("KFS doesn't think " + basedir
						+ " is a dir!");
				System.exit(1);
			}

			String path = new String(basedir + "/foo.1");
			KfsOutputChannel outputChannel;
			if ((outputChannel = kfsAccess.kfs_create(path)) == null) {
				System.out.println("Unable to call create");
				System.exit(1);
			}

			long mTime = kfsAccess.kfs_getModificationTime(path);
			Date d = new Date(mTime);
			System.out.println("Modification time for: " + path + " is: "
					+ d.toString());
			String[] entries;
			if ((entries = kfsAccess.kfs_readdir(basedir)) == null) {
				System.out.println("Readdir failed");
				System.exit(1);
			}

			System.out.println("Readdir returned: ");
			for (int i = 0; i < entries.length; i++) {
				System.out.println(entries[i]);
			}

			int numBytes = 2048;
			char[] dataBuf = new char[numBytes];

			generateData(dataBuf, numBytes);

			String s = new String(dataBuf);
			byte[] buf = s.getBytes();

			ByteBuffer b = ByteBuffer.wrap(buf, 0, buf.length);
			int res = outputChannel.write(b);
			if (res != buf.length) {
				System.out.println("Was able to write only: " + res);
			}

			assertEquals(outputChannel.tell(), buf.length);

			outputChannel.sync();

			outputChannel.close();
			KfsFileAttr[] fattr;
			if ((fattr = kfsAccess.kfs_readdirplus(basedir)) == null) {
				System.out.println("Readdirplus failed");
				System.exit(1);
			}

			System.out.println("Readdirplus returned: ");
			for (int i = 0; i < fattr.length; i++) {
				System.out.println("name: " + fattr[i].filename + " sz: "
						+ fattr[i].filesize);
			}

			System.out.println("Trying to lookup blocks for file: " + path);
			String[][] locs;
			if ((locs = kfsAccess.kfs_getDataLocation(path, 10L, 512L)) == null) {
				System.out.println("Get locs failed");
				System.exit(1);
			}

			System.out.println("Block Locations:");
			for (int i = 0; i < locs.length; i++) {
				System.out.print("chunk " + i + " : ");
				for (int j = 0; j < locs[i].length; j++) {
					System.out.print(locs[i][j] + " ");
				}
				System.out.println();
			}

			long sz = kfsAccess.kfs_filesize(path);

			if (sz != buf.length) {
				System.out.println("System thinks the file's size is: " + sz);
			}

			String npath = new String(basedir + "/foo.2");
			kfsAccess.kfs_rename(path, npath);

			if (kfsAccess.kfs_exists(path)) {
				System.out.println(path + " still exists after rename!");
				System.exit(1);
			}

			KfsOutputChannel outputChannel1 = kfsAccess.kfs_create(path);

			if (outputChannel1 != null) {
				outputChannel1.close();
			}

			if (!kfsAccess.kfs_exists(path)) {
				System.out.println(path + " doesn't exist");
				System.exit(1);
			}

			if (kfsAccess.kfs_rename(npath, path, false) == 0) {
				System.out.println("Rename with overwrite disabled succeeded!");
				System.exit(1);
			}

			kfsAccess.kfs_remove(path);

			if (!kfsAccess.kfs_isFile(npath)) {
				System.out.println(npath + " is not a normal file!");
				System.exit(1);
			}

			KfsInputChannel inputChannel = kfsAccess.kfs_open(npath);
			if (inputChannel == null) {
				System.out.println("open on " + npath + "failed!");
				System.exit(1);
			}

			buf = new byte[''];
			res = inputChannel.read(ByteBuffer.wrap(buf, 0, 128));

			s = new String(buf);
			for (int i = 0; i < 128; i++) {
				if (dataBuf[i] != s.charAt(i)) {
					System.out.println("Data mismatch at char: " + i);
				}
			}

			assertEquals(outputChannel.tell(), buf.length);

			inputChannel.seek(40L);

			sz = inputChannel.tell();
			if (sz != 40L) {
				System.out.println("After seek, we are at: " + sz);
			}

			inputChannel.close();

			kfsAccess.kfs_remove(npath);

			if (kfsAccess.kfs_rmdir(basedir) < 0) {
				System.out.println("unable to remove: " + basedir);
				System.exit(1);
			}
			System.out.println("All done...Test passed!");
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("Unable to setup KfsAccess");
			System.exit(1);
		}
	}

	private static void generateData(char[] buf, int numBytes) {
		for (int i = 0; i < numBytes; i++)
			buf[i] = ((char) (97 + randGen.nextInt(26)));
	}
}